const mongoose = require('mongoose');

/**
 * 验证题目请求数据
 * @param {Object} data - 题目数据对象
 * @throws {Error} 当验证失败时抛出错误
 */
const validateQuestionRequestBody = (data) => {

  // 基础必填字段验证
  const requiredFields = ['type', 'source'];
  const missingFields = requiredFields.filter(field => !data[field]);
  if (missingFields.length > 0) {
    throw new Error(`缺少必填字段：${missingFields.join(', ')}`);
  }
  // 传入字段数据类型验证 这是进入数据库之前的验证，当然在数据库层设置了数据格式，在本文件进行了错误捕获
  // 1. content字段验证 - 题目内容
  if (data.content && typeof data.content !== 'string') {
    throw new Error('文本类内容必须是字符串类型');
  }

  // 2. htmlContent字段验证 - 富文本内容
  if (data.htmlContent && typeof data.htmlContent !== 'string') {
    throw new Error('富文本内容必须是字符串类型');
  }

  // 3. image字段验证 - 题目图片 完全没有必要，因为这个字段不是由前端添加的而是在本controller中自行添加数据的
  // if (data.image && typeof data.image !== 'string') {
  //   throw new Error('1图片路径必须是字符串类型');
  // }

  // 4. type字段验证 - 题目类型（必须是ObjectId）
  if (typeof data.type !== 'string' || !mongoose.Types.ObjectId.isValid(data.type)) {
      throw new Error('题目类型必须是有效的ObjectId');
  } 

  // 5. options字段验证 - 选项
  if (data.options) {
    // 必须是数组类型
    if (!Array.isArray(data.options)) {
      throw new Error('选项必须是数组类型');
    }

    // 验证每个选项
    data.options.forEach((opt, index) => {
      // label验证
      if (opt.label && typeof opt.label !== 'string') {
        throw new Error(`选项${index + 1}的标签必须是字符串类型`);
      }

      // content验证
      if (opt.content && typeof opt.content !== 'string') {
        throw new Error(`选项${index + 1}的内容必须是字符串类型`);
      }

      // htmlContent验证
      if (opt.htmlContent && typeof opt.htmlContent !== 'string') {
        throw new Error(`选项${index + 1}的富文本内容必须是字符串类型`);
      }

      // image验证
      if (opt.image && typeof opt.image !== 'string') {
        throw new Error(`选项${index + 1}的图片路径必须是字符串类型`);
      }

      // isCorrect验证
      if (opt.isCorrect !== undefined && typeof opt.isCorrect !== 'boolean') {
        throw new Error(`选项${index + 1}的正确状态必须是布尔类型`);
      }
    });
  }

  // 6. answer字段验证 - 答案
  if (data.answer) {
    // 必须是字符串数组
    if (!Array.isArray(data.answer) || !data.answer.every(item => typeof item === 'string')) {
      throw new Error('答案必须是字符串数组');
    }
  }

  // 7. htmlAnswer字段验证 - 富文本答案
  if (data.htmlAnswer && typeof data.htmlAnswer !== 'string') {
    throw new Error('富文本答案必须是字符串类型');
  }

  // 8. imageAnswer字段验证 - 图片答案 完全没有必要，因为这个字段不是由前端添加的而是在本controller中自行添加数据的
  // if (data.imageAnswer && typeof data.imageAnswer !== 'string') {
  //   throw new Error('图片答案必须是字符串类型');
  // }

  // 9. points字段验证 - 分值
  if (data.points !== undefined) {
    const parsedPoints = Number(data.points);
    if (isNaN(parsedPoints)) {
      throw new Error('分值必须是数字');
    }

    if (parsedPoints < 0) {
      throw new Error('分值不能为负数');
    }
  }
  // 11.difficulty参数类型验证
  /**
   *  由于传来的数字可能不是真正的数字在这里进行判断
   * 
   *  isNaN()是判断传来的数字是不是NaN(Not a Number,不是一个数字 )，
   * 也就是说，如果传来的不是数字就返回true，否则false
   * 举例：isNaN("number")) //期望true  实际true
   * console.log(isNaN("1"))      //期望true  实际false
   * console.log(isNaN("0"))      //期望true  实际false
   * console.log(isNaN("true"))   //期望true  实际false
   * console.log(isNaN(0))        //期望false 实际false
   * 但是，它在判断的时候会强制先转化类型再判断，就会产生错误，举例如下
   * console.log(isNaN("number")) //期望true  实际true
   * console.log(isNaN("1"))      //期望true  实际false
   * console.log(isNaN("0"))      //期望true  实际false
   * console.log(isNaN("true"))   //期望true  实际false
   * console.log(isNaN(0))        //期望false 实际false
   * 再这里他甚至把非数字'1'当成了数字，把true当成了数字。
   * 
   * 所以为了准确判断，那就先强制转换为数字再判断。当然字符串数字'1'依然会被转化为数字
   * console.log(Number("number")) //NaN
   * console.log(Number("1"))      //1
   * console.log(Number("0"))      //0
   * console.log(Number("true"))   //NaN
   * console.log(Number(0))        //0
   * 尽管字符串'1'不是数字，按理说应该返回错误给res，但是转化后能成为数字也算可以。
   * 故采用先Number(),再NaN()判断。
   */

  const parsedDifficulty = Number(data.difficulty);
  if (isNaN(parsedDifficulty)) {
    throw new Error('难度参数必须是数字');
  }
  // 11. tags字段验证 - 知识点标签
  if (data.tags) {
    // 必须是数组
    if (!Array.isArray(data.tags)) {
      throw new Error('知识点标签必须是数组类型');
    }

    // 每个标签必须是有效的ObjectId
    for (let i = 0; i < data.tags.length; i++) {
      const tag = data.tags[i];
      if (typeof tag !== 'string' || !mongoose.Types.ObjectId.isValid(tag)) {
        throw new Error(`知识点标签${i + 1}必须是有效的ObjectId`);
      }
    }
  }

  // 12. source字段验证 - 题目来源
  if (data.source) {
    // 必须是数组
    if (!Array.isArray(data.source)) {
      throw new Error('题目来源必须是数组类型');
    }

    // 每个来源必须是有效的ObjectId
    for (let i = 0; i < data.source.length; i++) {
      const source = data.source[i];
      if (typeof source !== 'string' || !mongoose.Types.ObjectId.isValid(source)) {
        throw new Error(`题目来源${i + 1}必须是有效的ObjectId`);
      }
    }
  }
  // 1. 字段互斥检查
  if (data.content && data.htmlContent) {
    throw new Error('题目——文本内容和富文本内容不能同时提交');
  }

  // 2. 内容组合验证
  if (!data.content && !data.htmlContent) {
    throw new Error('题目——必须包含文本、富文本或图片至少一种');
  }



  // 4. 选择题选项验证 只要是体型为single(单选)或者multiple（多选）时，选项字段是必填的
  // 题目选项类型还没有完全确定（当然可以从mongoose中获取），且也没有检查的意义有没有选项都行（因为现在在开发的是纯图片版的选择题，选择题图片中自带选项，所以不能一概而论），所以暂时注销
  // if (data.type && ['single', 'multiple'].includes(data.type)) {
  //   if (!data.options || !Array.isArray(data.options)) {
  //     throw new Error('选择题必须提供选项数组');
  //   }

  //   // 验证每个选项的完整性
  //   data.options.forEach((opt, index) => {
  //     if (!opt.content && !opt.htmlContent && !opt.image) {
  //       throw new Error(`选项${index + 1}必须包含文本、富文本或图片至少一种`);
  //     }
  //   });
  // }
};

module.exports = { validateQuestionRequestBody };